import 'dart:async';
import 'dart:io';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:gbk2utf8/gbk2utf8.dart';

import '../../../app_files.dart';
import 'ble_log.dart';
import 'ble_model.dart';
import 'ble_utils.dart';
export 'ble_model.dart';

class XaBleManager {
  ///服务器ip
  static const String host = '123.58.242.24';

  /// 服务器端口
  static const int port = 7941;

  static const String appCode = 'FE';

  static XaBleManager _globalXaBleManager;

  static XaBleManager get instance => _globalXaBleManager ??= XaBleManager();

  Socket _socket;
  FlutterBlue flutterBlue = FlutterBlue.instance;
  String _toConnect;
  BluetoothDevice _device;
  String _bleId;

  String get currentBleId => _bleId;
  StreamSubscription _connectStatusSc;
  StreamSubscription _receiveContentSc;
  BluetoothDeviceState connectStatus = BluetoothDeviceState.disconnected;

  BluetoothCharacteristic _receiveCharacteristic;
  BluetoothCharacteristic _sendCharacteristic;
  final String _uuidService = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
  final String _uuidSend = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';
  final String _uuidReceive = '6e400003-b5a3-f393-e0a9-e50e24dcca9e';

  String _receiveContent = '';
  String _randomKey = '';

  String get currentRandomKey => _randomKey;

  final StreamController<String> _bleContentStreamController =
  StreamController<String>.broadcast();

  final StreamController<String> _socketContentStreamController =
  StreamController<String>.broadcast();

  XaBleManager() {
    _init();
  }

  _init() async {}

  Future<int> connect(String sn) async {
    if (connectStatus == BluetoothDeviceState.connected) {
      return 0;
    }
    _sendCharacteristic = _receiveCharacteristic = null;
    _device = null;
    _randomKey = '';
    _bleId = BleUtils.patchHexString(sn, 16);
    LogUtils.debug(_bleId);
    _toConnect = BleUtils.encode2(_bleId);
    try {
      List<ScanResult> res =
      await flutterBlue.startScan(timeout: Duration(seconds: 4));
      for (ScanResult r in res) {
        if (r.device.name != null) {
          if (r.advertisementData.manufacturerData.values.isNotEmpty) {
            String res = BleUtils.bytesToHexString(
                r.advertisementData.manufacturerData.values.first);
            if (res == _toConnect) {
              _device = r.device;
            }
          }
        }
      }
    }
    catch (e) {
      return -4;
    }
    if (_device == null) {
      return -1;
    }
    if (_connectStatusSc != null) {
      _connectStatusSc.cancel();
      _connectStatusSc = null;
    }
    _connectStatusSc = _device.state.listen((BluetoothDeviceState state) async {
      connectStatus = state;
      if (connectStatus == BluetoothDeviceState.connected) {
        print('已连接蓝牙卡');
      }
    });
    print('找到设备 连接中');
    _device.connect();
    await _device.state.firstWhere((s) => s == BluetoothDeviceState.connected);
    print('连接成功');
    await Future.delayed(Duration(seconds: 5));
    print('1111');
    List<BluetoothService> services = await _device.discoverServices();
    print('2222');
    services.forEach((service) async {
      if (service.uuid.toString().toUpperCase() == _uuidService.toUpperCase()) {
        List<BluetoothCharacteristic> characteristics = service.characteristics;
        characteristics.forEach((characteristic) {
          if (characteristic.uuid.toString() == _uuidReceive) {
            _receiveCharacteristic = characteristic;
            print('33333');
            _dataCallbackBle();
            print('4444');
          }
          if (characteristic.uuid.toString().toUpperCase() ==
              _uuidSend.toUpperCase()) {
            _sendCharacteristic = characteristic;
            print('5555');
          }
        });
      }
    });
    if (_receiveCharacteristic == null || _sendCharacteristic == null) {
      return -2;
    }
    await Future.delayed(Duration(seconds: 3));
    var r = await _doHandshake();
    if (r != null) return 0;
    return -3;
  }

  autoRequestAuth(String uuid, BuildContext context) async {
    CommonUtils.showWaitLoading(context, descText: '读卡中');
    XABleResponse keyData = await getKeyData();
    if (keyData == null) {
      Navigator.pop(context);
      CommonUtils.showAlertView(context, '鉴权13 失败');
      return false;
    }
    XABleResponse writeKey15Res = await authorKeyData('15', keyData, uuid);
    if (writeKey15Res == null) {
      Navigator.pop(context);
      CommonUtils.showAlertView(context, '鉴权15 失败');
      return false;
    }
    if (writeKey15Res.code != '00') {
      Navigator.pop(context);
      CommonUtils.showAlertView(
          context, '${writeKey15Res.error}  ${writeKey15Res.code}');
      return false;
    }
    XABleResponse writeKey17Res =
    await authorKeyData('17', writeKey15Res, uuid);
    if (writeKey17Res == null) {
      Navigator.pop(context);
      CommonUtils.showAlertView(context, '鉴权17 失败');
      return false;
    }
    if (writeKey17Res.code != '00') {
      Navigator.pop(context);
      CommonUtils.showAlertView(
          context, '${writeKey17Res.error}  ${writeKey17Res.code}');
      return false;
    }
    Navigator.pop(context);
    return true;
  }

  disconnect() async {
    if (connectStatus != BluetoothDeviceState.connected) {
      LogUtils.debug('尚未建立连接');
      return;
    }
    return _device.disconnect();
  }

  _dataCallSendBle(String command1) async {
    try {
      if (command1.length > 40) {
        bool res = await _dataCallSendBle(command1.substring(0, 40));
        if (res) {
          res = await _dataCallSendBle(command1.substring(40));
        }
        return res;
      } else {
        LogUtils.debug('发送数据：$command1');
        await _sendCharacteristic.write(BleUtils.hexStringToByte(command1));
        return true;
      }
    } catch (e) {
      LogUtils.debug('数据发送失败：$command1');
      return false;
    }
  }

  _dataCallbackBle() async {
    if (_receiveContentSc != null) {
      _receiveContentSc.cancel();
      _receiveContentSc = null;
    }
    _receiveCharacteristic.setNotifyValue(true);
    _receiveContentSc = _receiveCharacteristic.value.listen((value) async {
      if (value == null) {
        return;
      }
      String string = BleUtils.bytesToHexString(value);
      // LogUtils.debug('数据：$string');
      _receiveContent = _receiveContent + string;
      if (_checkReceiveContent(_receiveContent)) {
        print("蓝牙返回数据: $_receiveContent");
        await Future.delayed(Duration(seconds: 1));
        _bleContentStreamController.add(_receiveContent);
        _receiveContent = '';
      }
    });
  }

  bool _checkReceiveContent(String content) {
    bool isEnd = false;
    if (content.endsWith('16') && content.length > 4) {
      if (BleUtils.makeChecksum(content.substring(0, content.length - 4))
          .toLowerCase() ==
          content
              .substring(content.length - 4, content.length - 2)
              .toLowerCase()) {
        isEnd = true;
      }
    }
    return isEnd;
  }

  _doHandshake() async {
    _receiveContent = '';
    List<int> id3 = BleUtils.encode1(_bleId);
    XABleRequest handleReq = XABleRequest(
        cmd: '11', deviceId: _bleId, data: BleUtils.bytesToHexString(id3));
    return _doSendToBleCard(handleReq);
  }

  getUUID() async {
    _receiveContent = '';
    XABleRequest handleReq = XABleRequest(
      cmd: '09',
      deviceId: _bleId,
    );
    return _doSendToBleCard(handleReq);
  }

  getKeyData() async {
    XABleRequest handleReq = XABleRequest(
      cmd: '13',
      deviceId: _bleId,
    );
    return _doSendToBleCard(handleReq);
  }

  readCiphertextData() async {
    XABleRequest handleReq = XABleRequest(
      cmd: '03',
      deviceId: _bleId,
    );
    return _doSendToBleCard(handleReq);
  }

  writeCiphertextData(String data) async {
    XABleRequest handleReq =
    XABleRequest(cmd: '07', deviceId: _bleId, data: data);
    return _doSendToBleCard(handleReq);
  }

  readDeviceData() async {
    XABleRequest handleReq = XABleRequest(
      cmd: '01',
      deviceId: _bleId,
    );
    return _doSendToBleCard(handleReq);
  }

  queryNetwork() async {
    XABleRequest handleReq =
    XABleRequest(cmd: '05', deviceId: _bleId, data: '10');
    return _doSendToBleCard(handleReq);
  }

  /// cmd 15 和 17
  writeKeyData(String cmd, String data) async {
    XABleRequest handleReq =
    XABleRequest(cmd: cmd, deviceId: _bleId, data: data);
    return _doSendToBleCard(handleReq);
  }

  authorKeyData(String cmd, XABleResponse keyData, String uuid) async {
    XAServiceRequestModel request = XAServiceRequestModel.fromBleRes(
        uuid, keyData,
        reqType: cmd == '17' ? '20' : '10');
    _randomKey = request.keyValue;
    XAServiceResponseModel socketResponse =
    await sendToService(request.toString());
    if (socketResponse.status == '02') {
      await Future.delayed(Duration(seconds: 2));
      socketResponse = await sendToService(request.toString());
    }
    if (socketResponse.status != '00') {
      XABleResponse errRes =
      XABleResponse(code: socketResponse.status, error: '加密机器状态异常,请重试');
      return errRes;
    }
    XABleResponse writeKeyRes =
    await writeKeyData(cmd, socketResponse.data + socketResponse.textEnd);
    return writeKeyRes;
  }

  decryptCardData(XABleResponse keyData, String uuid) async {
    XAServiceRequestModel request =
    XAServiceRequestModel.decryptReq(uuid, _randomKey, keyData.data);
    var res = await sendToService(request.toString());
    return res;
  }

  encryptCardData(WriteCardContentModel data, String uuid) async {
    String textEnd = BleUtils.getCRC(data.toString());
    XAServiceRequestModel request = XAServiceRequestModel(
      uuid: uuid,
      reqType: '30',
      data: data.toString() + textEnd,
      keyValue: _randomKey,
    );
    var res = await sendToService(request.toString());
    return res;
  }

  _doSendToBleCard(XABleRequest request) async {
    try {
      Completer<String> completer = Completer<String>.sync();
      bool res = await _dataCallSendBle(request.toString());
      if (res) {
        StreamSubscription subscription = _bleContentStreamController.stream
            .listen((event) => completer.complete(event));
        var result = await completer.future;
        XABleResponse res = XABleResponse.fromContent(result);
        await subscription.cancel();
        subscription = null;
        return res;
      }
    } catch (e) {
      return null;
    }
  }

  sendToService(String data) async {
    try {
      _socket = await Socket.connect(host, port, timeout: Duration(seconds: 2));
      //给服务器发消息

    } catch (e) {
      print("连接socket出现异常，e=${e.toString()}");
      return '连接socket出现异常，e=${e.toString()}';
    }
    if (_socket != null) {
      _socket.listen((newData) {
        String string = gbk.decode(newData);
        // String string = utf8.decode(newData);
        _socketContentStreamController.add(string);
      }, onError: (e) {
        _socket = null;
        print('socket onError');
      }, onDone: () {
        _socket = null;
        print('socket onDone');
      }, cancelOnError: true);

      try {
        Completer<String> completer = Completer<String>();
        StreamSubscription subscription = _socketContentStreamController.stream
            .listen((event) => completer.complete(event));
        LogUtils.debug("给服务端发送消息，:$data");
        List<int> list = gbk.encode(data);
        _socket.add(list);
        var result = await completer.future;
        LogUtils.debug('服务器返回: $result');
        await subscription.cancel();
        subscription = null;
        await _socket.close();
        XAServiceResponseModel responseModel =
        XAServiceResponseModel.fromSocket(result);
        return responseModel;
      } catch (e) {
        print("send捕获异常：，e=${e.toString()}");
        return 'send捕获异常：，e=${e.toString()}';
      }
    }
  }
}
